home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / viewers / pcshow / vga.asm < prev   
Assembly Source File  |  1991-07-01  |  12KB  |  484 lines

  1. ;    
  2. ;    VGA support routines for raster oriented graphics
  3. ;
  4. ;    Quincey Koziol        June 1988
  5. ;
  6. ;    National Center for Supercomputing Applications,    University of Illinois
  7. ;    153    Water Resources Building
  8. ;    605 E. Springfield Ave.
  9. ;    Champaign, Ill    61820
  10. ;    (217)244-0072
  11. ;
  12.     TITLE      VGA GRAPHICS SUPPORT
  13.     INCLUDE DOS.MAC
  14.     SETX
  15.     PSEG
  16.     PUBLIC    PUTMAPV,GETMAP,VGALINE1,VGAMODE;,VGAOFF,VGAON,VGAPT
  17.     PUBLIC    SHOWPALV,NOPALV,OUTLINEV
  18. ;
  19. ;    take three arrays of color tables and interleave them into the
  20. ;    VGA registers in the fashion Red, Green, Blue.
  21. ;
  22.  
  23. PUTMAPV    PROC    FAR
  24.     PUSH    BP
  25.     MOV        BP,SP
  26.     PUSH    DS
  27.     PUSH    ES
  28. ;
  29.     MOV    AX,[BP+X+2]
  30.     MOV    DS,AX            ; WHERE TO GET MAPS (SEG)
  31.     MOV    SI,[BP+X]        ; WHERE TO GET RED
  32.     MOV DI,[BP+X+4]        ; WHERE TO GET GREEN
  33.     MOV BP,[BP+X+8]        ; WHERE TO GET BLUE
  34.     MOV    DX,03C8H        ; I/O PORT FOR PEL TABLE
  35.     MOV AL,0            ; VALUE FOR BEGINNING OF TABLE
  36.     OUT DX,AL            ; START OUTPUTTING VALUES
  37.     INC DX                ; INCREMENT DX TO OUTPUT TABLE
  38.     MOV CX,256            ; LENGTH OF THE TABLE IN BYTE TRIPLES
  39.  
  40. DORGB:
  41.     MOV AL,DS:[SI]        ; GET A RED BYTE
  42.     SHR AL,1
  43.     SHR AL,1            ; GET RID OF TWO HIGHEST BITS
  44.     OUT DX,AL            
  45.     INC SI
  46. ;
  47.     MOV AL,DS:[DI]        ; GET A GREEN BYTE
  48.     SHR    AL,1
  49.     SHR AL,1            ; GET RID OF TWO HIGHEST BITS
  50.     OUT DX,AL
  51.     INC DI
  52. ;
  53.     MOV    AL,DS:[BP]        ; GET A BLUE BYTE
  54.     SHR AL,1
  55.     SHR AL,1            ; GET RID OF TWO HIGHEST BITS
  56.     OUT DX,AL            
  57.     INC BP
  58. ;
  59.     LOOP DORGB            ; CONTINUE PRINTING UNTIL ALL 768 BYTES ARE WRITTEN
  60. ;
  61.     POP    ES
  62.     POP    DS
  63.     POP    BP
  64.     RET
  65.  
  66. PUTMAPV    ENDP
  67.  
  68. GETMAP    PROC    FAR
  69.     RET
  70. GETMAP    ENDP
  71.  
  72. ;
  73. ;  Transfer line to vga screen
  74. ;
  75. ;   usage : vgaline1(x,y,buf,xoff,linelen)
  76. ;
  77. VGALINE1    PROC    FAR
  78.     PUSH    BP
  79.     MOV        BP,SP
  80.     PUSH    DS
  81.     PUSH    ES
  82.  
  83. OKBANK:
  84.     MOV    AX,0A000H    ; DATA BUFFER
  85.     MOV    ES,AX
  86.     MOV    SI,[BP+X+4]    ; WHERE DATA WILL COME FROM
  87.     MOV    AX,[BP+X+8]    ; GET THE X OFFSET INTO THE ARRAY
  88.     CMP    AX,0        ; CHECK FOR NEGATIVE OFFSET
  89.     JGE    OKSIGN        ; JUMP AROUND FIXING THE WINDOW
  90.     NEG    AX            ; TAKE THE OPPOSITE VALUE
  91.     ADD AX,[BP+X]    ; AND ADD IT TO THE POSITION ON THE SCREEN
  92.     MOV    [BP+X],AX    ; AND RE-STORE THE POSITION
  93.     MOV    AX,[BP+X+8]    ; GET THE NEGATIVE OFFSET AGAIN
  94.     ADD    AX,[BP+X+10]    ; REDUCE THE NUMBER OF BYTES TO COPY TO THE SCREEN
  95.     MOV    [BP+X+10],AX    ; AND STORE THE NUMBER OF BYTES AGAIN
  96. OKSIGN:
  97.     ADD    SI,AX        ; ADD THE OFFSET TO THE OFFSET OF THE ARRAY
  98. ;
  99.     MOV AX,[BP+X+6]    ; SEGMENT OF DATA
  100.     MOV DS,AX
  101. ;
  102.     MOV    AX,[BP+X+2]    ; GET Y VALUE AGAIN
  103.     MOV    DX,320        ; GET LENGTH OF A LINE
  104.     MUL    DX
  105.     JA    DONTFIX        ; IF DX IS ZERO THEN DON'T PLAY WITH THE SEGMENT
  106.     MOV    BX,ES        ; GET THE ES
  107.     ADD    BX,DX        ; INCREMENT THE ES
  108.     MOV    ES,BX        ; AND REPLACE IT
  109. DONTFIX:
  110.     ADD    AX,[BP+X]    ; X VALUE OF WHERE ON SCREEN ADDED IN
  111.     MOV    DI,AX        ; PREPARE FOR MOVS
  112.     MOV    CX,[BP+X+10]    ; HOW MANY BYTES?
  113. BLAST:
  114.     REP    MOVSB
  115.  
  116.     POP    ES
  117.     POP    DS
  118.     POP    BP
  119.     RET
  120. VGALINE1    ENDP
  121.  
  122. ifdef QAK
  123. ;  point on vga screen
  124. ;
  125. ;   usage : vgapt(x,y,color)
  126. ;
  127. VGAPT    PROC    FAR
  128.     PUSH    BP
  129.     MOV        BP,SP
  130.     PUSH    DS
  131.     PUSH    ES
  132.  
  133. ;
  134. ;   READY TO PUT THE POINT
  135. ;
  136. POKBANK:
  137.     MOV    AX,0A000H    ; DATA BUFFER
  138.     MOV    ES,AX
  139.  
  140.     MOV    AX,[BP+X+2]    ; GET Y VALUE AGAIN
  141.     MOV    DX,320
  142.     MUL    DX
  143.     ADD    AX,[BP+X]    ; X VALUE OF WHERE ON SCREEN ADDED IN
  144.  
  145.     MOV    DI,AX        ; PREPARE FOR MOVS
  146.     MOV    AL,[BP+X+4]    ; GET COLOR TO PUT THERE
  147.  
  148.     STOSB            ; PUT IT
  149.  
  150.     POP    ES
  151.     POP    DS
  152.     POP    BP
  153.     RET
  154. VGAPT    ENDP
  155. endif
  156.  
  157. VGAMODE        PROC    FAR
  158.     PUSH    BP
  159.     MOV        BP,SP
  160.     PUSH    DS
  161.     PUSH    ES
  162.     
  163.     MOV        AX,[BP+X]        ;GET SCREEN MODE TO SWITCH TO
  164.     MOV        AH,00H            ;ENTER VIDEO_IO ROUTINE (SET MODE=0)
  165.     INT        10H                ;VIDEO INTERUPT
  166.  
  167.     POP    ES
  168.     POP    DS
  169.     POP    BP
  170.     RET
  171. VGAMODE    ENDP
  172.  
  173. ifdef QAK
  174. VGAOFF        PROC    FAR
  175.     PUSH    BP
  176.     MOV        BP,SP
  177.     PUSH    DS
  178.     PUSH    ES
  179.     
  180.     MOV        DX,03C4H        ;ADDRESS OF THE SEQ CONTROLLER
  181.     MOV        AL,01H            ;INDEX OF THE CLOCKING MODE REGISTER
  182.     OUT        DX,AL            ;SET UP TO READ THE CLOCKING MODE REGISTER
  183.     MOV        DX,03C5H        ;ADDRESS TO READ FROM
  184.     IN        AL,DX            ;GET THE CLOCKING MODE REGISTER
  185.     OR        AL,20H            ;MASK OFF THE SCREEN ENABLE BIT    
  186.     MOV        BL,AL            ;KEEP THAT AROUND
  187.     MOV        DX,03C4H        ;ADDRESS OF THE SEQ CONTROLLER
  188.     MOV        AL,01H            ;INDEX OF THE CLOCKING REGISTER
  189.     OUT        DX,AL            ;SET UP TO WRITE BACK THE CLOCKING MODE REGISTER
  190.     INC        DX                ;SET TO ADDRESS TO WRITE TO
  191.     MOV        AL,BL            ;GET BACK THE PROPER VALUE
  192.     OUT        DX,AL            ;TURNS OFF THE VGA SCREEN
  193.  
  194.     POP    ES
  195.     POP    DS
  196.     POP    BP
  197.     RET
  198. VGAOFF    ENDP
  199.  
  200. VGAON        PROC    FAR
  201.     PUSH    BP
  202.     MOV        BP,SP
  203.     PUSH    DS
  204.     PUSH    ES
  205.     
  206.     MOV        DX,03C4H        ;ADDRESS OF THE SEQ CONTROLLER
  207.     MOV        AL,01H            ;INDEX OF THE CLOCKING MODE REGISTER
  208.     OUT        DX,AL            ;SET UP TO READ THE CLOCKING MODE REGISTER
  209.     INC        DX                ;ADDRESS TO READ FROM
  210.     IN        AL,DX            ;GET THE CLOCKING MODE REGISTER
  211.     AND        AL,0DFH            ;TURN ON THE SCREEN ENABLE BIT    
  212.     MOV        BL,AL            ;KEEP THAT AROUND
  213.     MOV        DX,03C4H        ;ADDRESS OF THE SEQ CONTROLLER
  214.     MOV        AL,01H            ;INDEX OF THE CLOCKING REGISTER
  215.     OUT        DX,AL            ;SET UP TO WRITE BACK THE CLOCKING MODE REGISTER
  216.     INC        DX                ;SET TO ADDRESS TO WRITE TO
  217.     MOV        AL,BL            ;GET BACK THE PROPER VALUE
  218.     OUT        DX,AL            ;TURNS ON THE VGA SCREEN
  219.  
  220.     POP    ES
  221.     POP    DS
  222.     POP    BP
  223.     RET
  224. VGAON    ENDP
  225. endif
  226.  
  227. ;
  228. ;    showpalv(&palstore,pal_xoff,pal_yoff);
  229. ;    
  230. SHOWPALV        PROC    FAR
  231.     PUSH    BP
  232.     MOV        BP,SP
  233.     PUSH    DS
  234.     PUSH    ES
  235.  
  236.  
  237.     MOV     AX,[BP+X]        ;GET OFFSET OF ARRAY
  238.     MOV        DI,AX
  239.     MOV        AX,[BP+X+2]        ;GET SEGMENT OF STORAGE ARRAY
  240.     MOV        ES,AX            
  241.  
  242.     MOV        AX,[BP+X+6]        ;GET LINE TO START PALETTE ON
  243.     MOV        DX,320            ;GET THE LINE LENGTH
  244.     MUL        DX                ;GET THE OFFSET INTO THE SCREEN
  245.     ADD        AX,[BP+X+4]        ;ADD IN THE X OFFSET
  246.     JNC        NO_ROLLOVER        ;ADDITION DIDN'T CARRY
  247.     INC        DX                ;INCREMENT THE DX REGISTER ON A CARRY
  248. NO_ROLLOVER:
  249.     MOV        SI,AX            ;KEEP TRACK OF THE OFFSET
  250.     MOV        BX,SI            ;IN TWO PLACES
  251.     MOV        AX,320            ;GET THE LINE LENGTH
  252.     MOV        DX,8            ;GET THE NUMBER OF LINES
  253.     MUL        DX                ;GET THE NUMBER OF BYTES TO COPY
  254.     MOV        CX,AX            ;MOVE INTO COUNTER
  255.     MOV        AX,0A000H
  256.     MOV        DS,AX            ;GET THE SEGMENT FOR THE SOURCE
  257. ZIP:
  258.     REP        MOVSB            ;COPY THAT SECTION OF SCREEN
  259.     
  260.     MOV        CH,0            ;THE NUMBER OF LINES COPIED SO FAR
  261.     MOV        CL,00            ;THE NUMBER OF PIXELS
  262. TOP1:
  263.     MOV        SI,BX            ;GET THE CORRECT OFFSET TO BE COPIED TO
  264.     MOV        AX,0A000H
  265.     MOV        ES,AX            ;GET THE SEGMENT TO BE COPIED TO
  266. TOP2:
  267.     MOV        ES:[SI],CL        ;COPY ACROSS THE SCREEN INCREMENTING VALUES
  268.     INC        SI                ;MOVE TO NEXT PIXEL
  269.     INC        CL                ;INCREMENT COUNTER
  270.     JNE        TOP2            ;IF COUNTER NOT EQUAL TO ZERO THEN COPY AGAIN
  271.     
  272.     ADD        BX,320            ;MOVE DOWN TO NEXT LINE
  273.     INC        CH                ;INCREMENT THE LINE COUNTER
  274.     CMP        CH,8            ;CHECK IF ALL THE LINES ARE DONE
  275.     JNE        TOP1            ;IF LINE COUNT <8 THEN COPY ANOTHER LINE
  276.  
  277.     POP    ES
  278.     POP    DS
  279.     POP    BP
  280.     RET
  281. SHOWPALV    ENDP
  282.  
  283. ;
  284. ;    nopalv(&palstore,pal_xoff,pal_yoff);
  285. ;
  286. NOPALV        PROC    FAR
  287.     PUSH    BP
  288.     MOV        BP,SP
  289.     PUSH    DS
  290.     PUSH    ES
  291.  
  292.     MOV     AX,[BP+X]        ;GET OFFSET OF ARRAY
  293.     MOV        SI,AX
  294.     MOV        AX,[BP+X+2]        ;GET SEGMENT OF STORAGE ARRAY
  295.     MOV        DS,AX            
  296.  
  297.     MOV        AX,[BP+X+6]        ;GET LINE TO COPY SCREEN BACK ONTO
  298.     MOV        DX,320            ;GET THE LINE LENGTH
  299.     MUL        DX                ;GET THE OFFSET INTO THE SCREEN
  300.     ADD        AX,[BP+X+4]        ;ADD IN THE X OFFSET
  301.     JNC        NO_ROLL2        ;ADDITION DIDN'T CARRY
  302.     INC        DX                ;INCREMENT THE DX REGISTER ON A CARRY
  303. NO_ROLL2:
  304.     MOV        DI,AX            ;KEEP TRACK OF THE OFFSET
  305.     MOV        AX,320            ;GET THE LINE LENGTH
  306.     MOV        DX,8            ;GET THE NUMBER OF LINES
  307.     MUL        DX                ;GET THE NUMBER OF BYTES TO COPY
  308.     MOV        CX,AX            ;MOVE INTO COUNTER
  309.     MOV        AX,0A000H
  310.     MOV        ES,AX            ;GET THE SEGMENT FOR THE SOURCE
  311. ZOOM:
  312.     REP        MOVSB            ;COPY THAT SECTION OF SCREEN
  313.  
  314.     POP    ES
  315.     POP    DS
  316.     POP    BP
  317.     RET
  318. NOPALV    ENDP
  319.  
  320. ;
  321. ;  Invert A BOX ON THE SCREEN
  322. ;
  323. ;   usage : outlinev(x1,y1,x2,y2)
  324. ;
  325. OUTLINEV    PROC    FAR
  326.     PUSH    BP
  327.     MOV    BP,SP
  328.     PUSH    DS
  329.     PUSH    ES
  330.  
  331.     MOV    AX,[BP+X+2]    ; GET FIRST Y VALUE
  332.     CMP    AX,[BP+X+6]    ; COMPARE WITH THE SECOND Y - VALUE
  333.     JLE    CHECKX        ; OK ORDER GOTO CHECKING THE X VALUES
  334.     MOV    CX,AX        ; SWAP THE TWO VALUES
  335.     MOV    AX,[BP+X+6]    ;
  336.     MOV    [BP+X+2],AX    ;
  337.     MOV    AX,CX        ;
  338.     MOV    [BP+X+6],AX    ;
  339. CHECKX:
  340.     MOV    AX,[BP+X]    ; GET FIRST X VALUE
  341.     CMP    AX,[BP+X+4]    ; COMPARE WITH THE SECOND X - VALUE
  342.     JLE    MAKELEN        ; OK ORDER GOTO COMPUTING THE LENGTHS
  343.     MOV    CX,AX        ; SWAP THE TWO VALUES
  344.     MOV    AX,[BP+X+4]    ;
  345.     MOV    [BP+X],AX    ;
  346.     MOV    AX,CX        ;
  347.     MOV    [BP+X+4],AX    ;
  348. MAKELEN:            ; COMPUTE THE X AND Y WIDTHS FOR THE BOX TO BE INVERTED
  349.     MOV    AX,[BP+X+4]    ; GET THE LARGER OF THE TWO X VALUES
  350.     SUB    AX,[BP+X]    ; SUBTRACT THE SMALLER VALUE TO FIND THE LENGTH
  351.     ADD    AX,1        ;
  352.     MOV    [BP+X+4],AX    ; STORE IT IN THE OLD LOCATION FOR THE 2ND X VALUE
  353.     MOV    AX,[BP+X+6]    ; GET THE LARGER OF THE TWO Y VALUES
  354.     SUB    AX,[BP+X+2]    ; SUBTRACT THE SMALLER VALUE TO FIND THE LENGTH
  355.     SUB    AX,1        ; SUBTRACT TWO FOR THE TOP AND BOTTOM EDGES
  356.     CMP    AX,0        ; CHECK IF IT IS LESS THAN ZERO
  357.     JG     POSITIVE    ; JUMP AROUND ZEROING THE ACC.
  358.     MOV    AX,0
  359. POSITIVE:
  360.     MOV    [BP+X+6],AX    ; STORE IT IN THE OLD LOCATION FOR THE 2ND Y VALUE
  361.     MOV    AX,320        ; COMPUTE THE VALUE TO ADD TO THE DI FOR COMPLETE WRAPAROUND
  362.     SUB    AX,[BP+X+4]    ;
  363.     MOV    SI,AX        ; KEEP TRACK OF IT
  364.     
  365.     MOV    AX,0A000H    ; DATA BUFFER
  366.     MOV    ES,AX
  367. ;
  368.     MOV    AX,[BP+X+2]    ; GET Y VALUE AGAIN
  369.     MOV    DX,320        ; GET LENGTH OF A LINE
  370.     MUL    DX
  371.     JA    DONTFIXA    ; IF DX IS ZERO THEN DON'T PLAY WITH THE SEGMENT
  372.     MOV    BX,ES        ; GET THE ES
  373.     ADD    BX,DX        ; INCREMENT THE ES
  374.     MOV    ES,BX        ; AND REPLACE IT
  375. DONTFIXA:
  376.     ADD    AX,[BP+X]    ; X VALUE OF WHERE ON SCREEN ADDED IN
  377.     MOV    DI,AX        ; PREPARE FOR MOVS
  378.     MOV    CX,[BP+X+4]    ; HOW MANY BYTES?
  379. BLASTA:
  380.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  381.     NOT    AL        ; INVERT THE VALUE THERE
  382.     MOV    ES:[DI],AL    ; REPLACE THE VALUE
  383.     INC    DI        ; INCREMENT TO NEXT POSITION
  384.     LOOP     BLASTA        ; LOOP UNTIL ALL HAVE BEEN DONE
  385.  
  386.     ADD    DI,SI        ; MOVE OVER TO THE BEGINNING OF THE NEXT LINE
  387.     MOV    CX,[BP+X+6]    ; COUNT VALUE FOR THE NEXT SERIES
  388.     CMP    CX,0        ; CHECK FOR NO LINES IN BETWEEN
  389.     JLE    BLAST2A        ; JUMP AROUND PUTTING THE LINES IN BETWEEN
  390. BLAST2:
  391.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  392.     NOT    AL            ; INVERT IT
  393.     MOV    ES:[DI],AL    ; REPLACE THE INVERTED VALUE
  394.     ADD    DI,[BP+X+4]    ; GO TO THE LAST VALUE TO INVERT ON THAT LINE
  395.     SUB    DI,1        ;
  396.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  397.     NOT    AL        ; INVERT IT
  398.     MOV    ES:[DI],AL    ; REPLACE THE INVERTED VALUE
  399.     ADD    DI,SI        ; GET THE VALUE FOR THE BEGINNING OF THE NEXT LINE
  400.     INC    DI        ;
  401.     LOOP    BLAST2        ; DO THE NEXT LINE
  402.  
  403. BLAST2A:
  404.     MOV    CX,[BP+X+4]    ; PREPARE FOR LAST LINE
  405. BLAST3:
  406.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  407.     NOT    AL            ; INVERT THE VALUE THERE
  408.     MOV    ES:[DI],AL    ; REPLACE THE VALUE
  409.     INC    DI            ; INCREMENT TO NEXT POSITION
  410.     LOOP    BLAST3        ; LOOP UNTIL ALL HAVE BEEN DONE
  411.  
  412.     POP    ES
  413.     POP    DS
  414.     POP    BP
  415.     RET
  416. OUTLINEV    ENDP
  417. ;
  418. ;  Draw a 4x4 ball on the vga screen
  419. ;
  420. ;   usage : ball(x,y)
  421. ;
  422. BALL        PROC    FAR
  423.     PUSH    BP
  424.     MOV        BP,SP
  425.     PUSH    DS
  426.     PUSH    ES
  427.  
  428.     MOV    AX,0A000H    ; DATA BUFFER
  429.     MOV    ES,AX
  430. ;
  431.     MOV    AX,[BP+X+2]    ; GET Y VALUE
  432.     MOV    DX,320        ; GET LENGTH OF A LINE
  433.     MUL    DX
  434.     JA    DONTFIXB    ; IF DX IS ZERO THEN DON'T PLAY WITH THE SEGMENT
  435.     MOV    BX,ES        ; GET THE ES
  436.     ADD    BX,DX        ; INCREMENT THE ES
  437.     MOV    ES,BX        ; AND REPLACE IT
  438. DONTFIXB:
  439.     ADD    AX,[BP+X]    ; X VALUE OF WHERE ON SCREEN ADDED IN
  440.     MOV    DI,AX        ; PREPARE FOR MOVS
  441.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  442.     NOT    AL            ; INVERT IT
  443.     MOV    ES:[DI],AL    ; REPLACE THE VALUE
  444.     INC    DI            ; MOVE OVER ONE BYTE
  445.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  446.     NOT    AL            ; INVERT IT
  447.     MOV    ES:[DI],AL    ; REPLACE THE VALUE
  448.  
  449.     ADD    DI,318        ; MOVE TO THE NEXT LINE
  450.     MOV    CX,4        ; HOW MANY BYTES?
  451. BLASTB:
  452.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  453.     NOT    AL            ; INVERT THE VALUE THERE
  454.     MOV    ES:[DI],AL    ; REPLACE THE VALUE
  455.     INC    DI            ; INCREMENT TO NEXT POSITION
  456.     LOOP BLASTB        ; LOOP UNTIL ALL HAVE BEEN DONE
  457.  
  458.     MOV    CX,4        ; COUNT VALUE FOR THE NEXT SERIES
  459.     ADD    DI,316        ; MOVE OVER TO THE BEGINNING OF THE NEXT LINE
  460. BLASTC:
  461.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  462.     NOT    AL            ; INVERT IT
  463.     MOV    ES:[DI],AL    ; REPLACE THE INVERTED VALUE
  464.     INC DI            ;
  465.     LOOP    BLASTC    ; DO THE NEXT LINE
  466.  
  467.     ADD    DI,317        ; MOVE ONE BYTE OVER INTO THE NEXT LINE
  468.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  469.     NOT    AL            ; INVERT IT
  470.     MOV    ES:[DI],AL    ; REPLACE THE VALUE
  471.     INC    DI            ; MOVE OVER ONE BYTE
  472.     MOV    AL,ES:[DI]    ; GET THE VALUE TO INVERT
  473.     NOT    AL            ; INVERT IT
  474.     MOV    ES:[DI],AL    ; REPLACE THE VALUE
  475.  
  476.     POP    ES
  477.     POP    DS
  478.     POP    BP
  479.     RET
  480. BALL    ENDP
  481.  
  482.     ENDPS
  483.     END
  484.